
package com.zpz.framework.zpzoauth.config.oauth.authorization;

import com.zpz.framework.zpzoauth.common.result.ZpzOauthResultMsg;
import com.zpz.framework.zpzoauth.common.result.ZpzOauthResultStatus;
import com.zpz.framework.zpzoauth.common.utils.ZpzOauthCommonConstant;
import com.zpz.framework.zpzoauth.config.oauth.authorization.exouath.ZpzOauthIntegrationAuthenticationFilter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import javax.sql.DataSource;
import java.util.*;

/**
 * @author zhangpanzhi
 * @time 2019-07-09
 * @description 未经本人允许请勿随便改动，尊重劳动
 * */
@Configuration
@Order(Integer.MIN_VALUE)
@EnableAuthorizationServer
public class ZpzOauthAuthorizationConfig extends AuthorizationServerConfigurerAdapter {
    private static Logger logger = LoggerFactory.getLogger(ZpzOauthAuthorizationConfig.class);
    @Autowired
    private DataSource dataSource;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private ZpzOauthIntegrationUserDetailsService zpzOauthIntegrationUserDetailsService;
    @Autowired
    private ZpzOauthIntegrationAuthenticationFilter zpzOauthIntegrationAuthenticationFilter;
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(new JdbcClientDetailsService(dataSource));
    }
    /*打印出完整的堆栈跟踪*/
    @Bean
    public WebResponseExceptionTranslator loggingExceptionTranslator() {
        return new DefaultWebResponseExceptionTranslator() {
            //去掉响应结果中泛型的限制，就可以返回任何自定义的对象。
            @Override
            public ResponseEntity translate(Exception e) throws Exception {
                ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
                HttpHeaders headers = new HttpHeaders();
                headers.setAll(responseEntity.getHeaders().toSingleValueMap());
                OAuth2Exception responseParam = responseEntity.getBody();
                String message = responseParam.getMessage();
//                Class<? extends OAuth2Exception> aClass = responseParam.getClass();
                ZpzOauthResultMsg<Object> error = ZpzOauthResultMsg.error(e.getMessage());
                if (StringUtils.isNotBlank(message)){
                    if (message.contains("Invalid refresh token (expired):")){
                        //refresh_token过期
                        error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.GATE_WAY_10041);
                    }else if ((message.contains("坏的凭证")||message.contains("Bad credentials"))){
                        error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.GATE_WAY_10012);
                    }else if (message.contains("[ZPZ_DEFINED_OAUTH2_EXCEPTION]")){
                        if (message.contains("[10005]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10005);
                        }else if (message.contains("[-1010]")){
                            logger.info(String.format("错误异常------------------%s",message));
                            error=ZpzOauthResultMsg.error(message.split("\\[-1010\\]")[1]);
                        }else if (message.contains("[10006]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10006);
                        }else if (message.contains("[10007]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10007);
                        }else if (message.contains("[10008]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10008);
                        }else if (message.contains("[10009]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10009);
                        }else if (message.contains("[10015]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10015);
                        }else if (message.contains("[10010]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10010);
                        }else if (message.contains("[10013]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.OAUTH_10013);
                        }else if (message.contains("[10041]")){
                            error=ZpzOauthResultMsg.customResultStatus(ZpzOauthResultStatus.GATE_WAY_10041);
                        }
                    }
                }
                return ResponseEntity.ok(error);
            }
        };
    }
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        //token增强配置
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(
                Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
        endpoints
                .tokenStore(jwtTokenStore())
                .tokenEnhancer(tokenEnhancerChain)
                .authenticationManager(authenticationManager)
                .reuseRefreshTokens(false)
                .userDetailsService(zpzOauthIntegrationUserDetailsService)
                .exceptionTranslator(loggingExceptionTranslator());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .allowFormAuthenticationForClients()
                .tokenKeyAccess("isAuthenticated()")
                .checkTokenAccess("permitAll()")
                .addTokenEndpointAuthenticationFilter(zpzOauthIntegrationAuthenticationFilter);
    }



    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        ZpzJwtAccessTokenConverter jwtAccessTokenConverter = new ZpzJwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey(ZpzOauthCommonConstant.SIGN_KEY);
        return jwtAccessTokenConverter;
    }
    /**
     * jwt 生成token 定制化处理
     *
     * @return TokenEnhancer
     */
    @Bean
    public TokenEnhancer tokenEnhancer() {
        return (accessToken, authentication) -> {
            final Map<String, Object> additionalInfo = new HashMap<>(1);
            Collection<GrantedAuthority> authorities = authentication.getAuthorities();
            String roles="";
            for (Iterator i =authorities.iterator(); i.hasNext();) {
                Object next = i.next();
                if (next!=null){
                    roles+=next.toString()+",";
                }
            }
            if (roles.endsWith(",")){
                roles=roles.substring(0,roles.lastIndexOf(","));
            }
            String grantType=null;
            OAuth2Request oAuth2Request = authentication.getOAuth2Request();
            if (oAuth2Request!=null){
                Map<String, String> requestParameters = oAuth2Request.getRequestParameters();
                if (requestParameters!=null){
                    grantType = requestParameters.get("auth_type");
                }
                if (!StringUtils.isNotBlank(grantType)){
                    grantType = oAuth2Request.getGrantType();
                }
            }
            additionalInfo.put("grant_type",grantType);
            additionalInfo.put("role",roles);
            additionalInfo.put("license", ZpzOauthCommonConstant.ZPZ_LICENSE);//扩展返回token
            additionalInfo.put("author", ZpzOauthCommonConstant.ZPZ_AUTHOR);//扩展返回token
            if (authentication!=null&&authentication.getUserAuthentication()!=null&&authentication.getUserAuthentication().getPrincipal()!=null){
                // client授权没有user
                ZpzOauthUserDetails user = (ZpzOauthUserDetails) authentication.getUserAuthentication().getPrincipal();
                additionalInfo.put("ucode", user.getUserCode());//扩展返回token
                additionalInfo.put("register_status", user.getRegisterStatus());//扩展返回token
            }
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        };
    }

}
